﻿using Fierce.Core.Context;
using Fierce.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.EntityFrameworkCore;

namespace Fierce.Core.DbSet
{
    /// <summary>
    /// 基本数据
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    internal class BaseDbSet<T> where T : EntityBase, new()
    {
        /// <summary>
        /// 数据上下文
        /// </summary>
        protected DataContext dbContext = null;

        /// <summary>
        /// 查询计算器
        /// </summary>
        /// <returns>查询计算器</returns>
        internal virtual IQueryable<T> Query()
        {
            return dbContext.Ef.Set<T>().AsNoTracking().OrderBy(m => m.InsertTime);
        }

        /// <summary>
        /// 查询计算器
        /// </summary>
        /// <param name="predicate">查询条件</param>
        /// <returns>查询计算器</returns>
        internal virtual IQueryable<T> Query(Expression<Func<T, bool>> predicate)
        {
            return Query().Where(predicate);
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="rows">行数</param>
        /// <param name="page">页码</param>
        /// <param name="entities">查询计算器</param>
        /// <returns>查询计算器</returns>
        internal virtual IQueryable<T> Pager(int rows, int page, IQueryable<T> entities = null)
        {
            if (entities == null) { entities = Query(); }

            return entities.Skip(rows * (page - 1)).Take(rows);
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="rows">行数</param>
        /// <param name="page">页码</param>
        /// <param name="sort">排序字段</param>
        /// <param name="order">排序方式</param>
        /// <param name="entities">查询计算器</param>
        /// <returns>查询计算器</returns>
        internal virtual IQueryable<T> Pager(int rows, int page, string sort, string order, IQueryable<T> entities = null)
        {
            if (entities == null) { entities = Query(); }

            ParameterExpression left = Expression.Parameter(typeof(T), "p");
            PropertyInfo property = typeof(T).GetProperty(sort);

            MemberExpression member = Expression.Property(left, property);
            LambdaExpression lambda = Expression.Lambda(member, left);

            order = order.Equals("asc") ? "OrderBy" : "OrderByDescending";

            Type[] types = new Type[] { typeof(T), property.PropertyType };
            UnaryExpression unary = Expression.Quote(lambda);
            Expression query = Expression.Call(typeof(Queryable), order, types, entities.Expression, unary);

            return entities.Provider.CreateQuery<T>(query).Skip(rows * (page - 1)).Take(rows);
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="rows">行数</param>
        /// <param name="page">页码</param>
        /// <param name="count">数据总数</param>
        /// <param name="entities">查询计算器</param>
        /// <returns>查询计算器</returns>
        internal virtual IQueryable<T> Pager(int rows, int page, out int count, IQueryable<T> entities = null)
        {
            if (entities == null) { entities = Query(); }

            count = entities.Count();

            return Pager(rows, page, entities);
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="rows">行数</param>
        /// <param name="page">页码</param>
        /// <param name="sort">排序字段</param>
        /// <param name="order">排序方式</param>
        /// <param name="count">数据总数</param>
        /// <param name="entities">查询计算器</param>
        /// <returns>查询计算器</returns>
        internal virtual IQueryable<T> Pager(int rows, int page, string sort, string order, out int count, IQueryable<T> entities = null)
        {
            if (entities == null) { entities = Query(); }

            count = entities.Count();

            return Pager(rows, page, sort, order, entities);
        }

        /// <summary>
        /// 设置数据对象
        /// </summary>
        /// <param name="context">数据对象</param>
        public void Init(DataContext context)
        {
            dbContext = context;
        }

        /// <summary>
        /// 主键查询
        /// </summary>
        /// <param name="key">键值</param>
        /// <returns>实体</returns>
        internal virtual T Get(string key)
        {
            return Get(m => m.ID == key);
        }

        /// <summary>
        /// 条件查询
        /// </summary>
        /// <param name="predicate">条件</param>
        /// <returns></returns>
        internal virtual T Get(Expression<Func<T, bool>> predicate)
        {
            return Query().FirstOrDefault(predicate);
        }

        #region 基础操作

        /// <summary>
        /// 添加实体
        /// </summary>
        /// <param name="entity">实体</param>
        internal virtual void Added(T entity)
        {
            entity.InitializationID();

            entity.InsertTime = DateTime.Now;
            entity.UpdateTime = DateTime.Now;

            dbContext.Ef.Set<T>().Attach(entity);
            dbContext.Ef.Entry<T>(entity).State = EntityState.Added;
        }

        /// <summary>
        /// 批量添加实体
        /// </summary>
        /// <param name="entities">实体集合</param>
        internal virtual void Added(IEnumerable<T> entities)
        {
            foreach (T entity in entities)
            {
                entity.InitializationID();

                entity.InsertTime = DateTime.Now;
                entity.UpdateTime = DateTime.Now;

                dbContext.Ef.Set<T>().Attach(entity);
                dbContext.Ef.Entry<T>(entity).State = EntityState.Added;
            }
        }

        /// <summary>
        /// 更改实体
        /// </summary>
        /// <param name="entity">实体</param>
        internal virtual void Modified(T entity)
        {
            entity.UpdateTime = DateTime.Now;

            dbContext.Ef.Set<T>().Attach(entity);
            dbContext.Ef.Entry<T>(entity).State = EntityState.Modified;
        }

        /// <summary>
        /// 批量更改实体
        /// </summary>
        /// <param name="entities">实体集合</param>
        internal virtual void Modified(IEnumerable<T> entities)
        {
            foreach (T entity in entities)
            {
                entity.UpdateTime = DateTime.Now;

                dbContext.Ef.Set<T>().Attach(entity);
                dbContext.Ef.Entry<T>(entity).State = EntityState.Modified;
            }
        }

        /// <summary>
        /// 主键删除实体
        /// </summary>
        /// <param name="key">键值</param>
        internal virtual void Deleted(string key)
        {
            Deleted(new T() { ID = key });
        }

        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="entity">实体</param>
        internal virtual void Deleted(T entity)
        {
            dbContext.Ef.Set<T>().Attach(entity);
            dbContext.Ef.Entry<T>(entity).State = EntityState.Deleted;
        }

        /// <summary>
        /// 批量删除实体
        /// </summary>
        /// <param name="entities">实体</param>
        internal virtual void Deleted(IEnumerable<T> entities)
        {
            foreach (T entity in entities)
            {
                dbContext.Ef.Set<T>().Attach(entity);
                dbContext.Ef.Entry<T>(entity).State = EntityState.Deleted;
            }
        }

        /// <summary>
        /// 条件删除实体
        /// </summary>
        /// <param name="predicate">条件</param>
        internal virtual void Deleted(Expression<Func<T, bool>> predicate)
        {
            Deleted(Query().Where(predicate));
        }

        #endregion
    }
}